package com.azier.kapacitor.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

import java.io.IOException;
import java.text.SimpleDateFormat;

/**
 * JSON 工具类
 *
 * @author 金建强(ptma@163.com)
 * @version 2015-10-21 20:45.
 */
public final class JsonUtil {

    private static ObjectMapper MAPPER;

    static {
        MAPPER = generateMapper(JsonInclude.Include.ALWAYS);
    }

    private JsonUtil(){
    }

    /**
     * 将json通过类型转换成对象
     *
     * <pre>
     *     {@link JsonUtil JsonUtil}.fromJson("{\"username\":\"username\", \"password\":\"password\"}", User.class);
     * </pre>
     *
     * @param json json字符串
     * @param clazz 泛型类型
     * @return 返回对象
     * @throws IOException
     */
    public static <T> T fromJson(String json, Class<T> clazz) throws IOException {
        return MAPPER.readValue(json, clazz);
    }

    /**
     * 将json通过类型转换成对象
     *
     * <pre>
     *     {@link JsonUtil JsonUtil}.fromJson("[{\"username\":\"username\", \"password\":\"password\"}, {\"username\":\"username\", \"password\":\"password\"}]", new TypeReference&lt;List&lt;User&gt;&gt;);
     * </pre>
     *
     * @param json json字符串
     * @param typeReference 引用类型
     * @return 返回对象
     * @throws IOException
     */
    public static <T> T fromJson(String json, TypeReference<T> typeReference) throws IOException {
        return MAPPER.readValue(json, typeReference);
    }

    /**
     * 将对象转换成json
     *
     * @param src 对象
     * @return 返回json字符串
     */
    public static <T> String toJson(T src) {
        return toJson(src, false);
    }

    /**
     * 将对象转换成json
     *
     * @param src 对象
     * @param pretty 是否格式化json
     * @param <T>
     * @return 返回json字符串
     */
    public static <T> String toJson(T src, boolean pretty) {
        try {
            if (src instanceof String) {
                return (String) src;
            }
            if (pretty) {
                return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(src);
            } else {
                return MAPPER.writeValueAsString(src);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将对象转换成json, 可以设置输出属性
     *
     * <pre>
     *     {@link JsonUtil JsonUtil}.toJson(user, {@link JsonInclude.Include Include.ALWAYS});
     * </pre>
     *
     * {@link JsonInclude.Include Include 对象枚举}
     * <ul>
     *     <li>{@link JsonInclude.Include Include.ALWAYS 全部列入}</li>
     *     <li>{@link JsonInclude.Include Include.NON_DEFAULT 字段和对象默认值相同的时候不会列入}</li>
     *     <li>{@link JsonInclude.Include Include.NON_EMPTY 字段为NULL或者""的时候不会列入}</li>
     *     <li>{@link JsonInclude.Include Include.NON_NULL 字段为NULL时候不会列入}</li>
     * </ul>
     *
     * @param src 对象
     * @param include 传入一个枚举值, 设置输出属性
     * @return 返回json字符串
     * @throws IOException
     */
    public static <T> String toJson(T src, JsonInclude.Include include) {
        try {
            if (src instanceof String) {
                return (String) src;
            } else {
                ObjectMapper customMapper = generateMapper(include);
                return customMapper.writeValueAsString(src);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将对象转换成json, 传入配置对象
     *
     * {@link ObjectMapper ObjectMapper}
     *
     * @see ObjectMapper
     *
     * @param src 对象
     * @param mapper 配置对象
     * @return 返回json字符串
     * @throws IOException
     */
    public static <T> String toJson(T src, ObjectMapper mapper) {
        try {
            if (null != mapper) {
                if (src instanceof String) {
                    return (String) src;
                } else {
                    return mapper.writeValueAsString(src);
                }
            } else {
                return toJson(src);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 当JSON里只含有Bean的部分属性時，更新一個已存在Bean，只覆盖該部分的属性.
     */
    public static void update(String jsonString, Object object) {
        try {
            MAPPER.readerForUpdating(object).readValue(jsonString);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * bean、array、List、Map --> json
     *
     * @param obj
     * @return json string
     * @throws Exception
     */
    public static String writeValueAsString(Object obj) {
        try {
            return MAPPER.writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 返回{@link ObjectMapper ObjectMapper}对象, 用于定制性的操作
     *
     * @return {@link ObjectMapper ObjectMapper}对象
     */
    public static ObjectMapper mapper() {
        return MAPPER;
    }

    public static ObjectMapper newMapper() {
        return generateMapper(JsonInclude.Include.ALWAYS);
    }

    /**
     * 创建只输出非Null的属性到Json字符串的Mapper.
     */
    public static ObjectMapper nonNullMapper() {
        return generateMapper(JsonInclude.Include.NON_NULL);
    }

    /**
     * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper.
     *
     * 注意，要小心使用, 特别留意empty的情况.
     */
    public static ObjectMapper nonEmptyMapper() {
        return generateMapper(JsonInclude.Include.NON_EMPTY);
    }

    private static ObjectMapper generateMapper(JsonInclude.Include include) {
        ObjectMapper customMapper = new ObjectMapper();
        // 设置输出时包含属性的风格
        customMapper.setSerializationInclusion(include);
        customMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        customMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        customMapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
        customMapper.configure(JsonGenerator.Feature.QUOTE_NON_NUMERIC_NUMBERS, true);
        //customMapper.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
        customMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 所有日期格式都统一为以下样式
        customMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        customMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object value, JsonGenerator jg, SerializerProvider sp) throws IOException {
                jg.writeString("");
            }
        });

        // Long 转 字符串
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        customMapper.registerModule(simpleModule);
        return customMapper;
    }

}
